import java.util.Scanner;

public class day4 {
    /**
     * 动态规划
     * BC140 杨辉三角
     * https://www.nowcoder.com/practice/e671c6a913d448318a49be87850adbcc?tpId=290&tqId=39928&ru=/exam/oj
     */
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        // dp[i][j]: 到达i,j位置的时候，所对应的杨慧三角的值
        int[][] dp = new int[n + 1][n + 1];
        // 初始化：多加的[0][0] 全初始化为0,因为0~n,0和0,0~n 下标是不会出现杨慧三角的值
        dp[1][1] = 1;
        for(int i = 2;i <= n;i++) {
            for(int j =1;j <= n;j++) {
                dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
            }
        }
        // 这样dp中存的就是 n 对应的所有杨慧三角的值
        for(int i = 1;i <= n;i++) {
            StringBuffer ret = new StringBuffer();
            for(int j = 1;j <= i;j++) {
                // 把dp[i][j]位置的数字转换为字符串，进行求取对应的长度，进而计算需要放多少个 " "
                int len = Integer.toString(dp[i][j]).length();
                for(int k = 0;k < 5 - len;k++) {
                    ret.append(" ");
                }
                ret.append(dp[i][j]);
            }
            System.out.println(ret.toString());
        }
    }


    /**
     * dfs + 回溯
     * NC242 单词搜索
     * https://www.nowcoder.com/practice/987f2981769048abaf6180ed63266bb2?tpId=196&tqId=39583&ru=/exam/oj
     */
    int m = 0;
    int n = 0;
    boolean[][] visit;
    public boolean exist (String[] board, String word) {
        // write code here
        m = board.length;
        n = board[0].length();
        visit = new boolean[m][n];
        for(int i = 0;i < m;i++) {
            for(int j = 0;j < n;j++) {
                if(board[i].charAt(j) == word.charAt(0)) {
                    // 第一个字符 判断结束，判断下一个，但是pos 是前一个位置
                    if(dfs(board,i,j,word,0) == true) {
                        return true;
                    }
                }
            }
        }
        return false;
    }
    int[] dx = {0,0,1,-1};
    int[] dy = {1,-1,0,0};
    public boolean dfs(String[] board,int i,int j,String word,int pos) {
        // pos为判断的次数，同样也是word对应要判断的位置的 前一个位置的下标
        if(pos == word.length() - 1) {
            return true;
        }
        visit[i][j] = true;
        for(int k = 0;k < 4;k++) {
            int x = i + dx[k],y = j + dy[k];
            if(x >= 0 && x < m && y >= 0 && y < n && !visit[x][y] && board[x].charAt(y) == word.charAt(pos + 1)) {
                // 往后走
                if(dfs(board,x,y,word,pos + 1)) {
                    return true;
                }
            }
        }
        // 到达这里需要进行回溯，因为没有往后继续走的条件，所以需要重新标记为没走过
        visit[i][j] = false;
        return false;
    }

    /**
     * 模拟
     * WY22 Fibonacci数列
     * https://www.nowcoder.com/practice/18ecd0ecf5ef4fe9ba3f17f8d00d2d66?tpId=122&tqId=33668&ru=/exam/oj
     * @param args
     */
    public static void main1(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int a = 0,b = 1,c = 1;
        // 找出第一次大于n的Fibonacci数
        while(n > c) {
            a = b;
            b = c;
            c = a + b;
        }
        // 找到之后想要变成Fibonacci数那么就在第一次大于的c和后面的b中决出
        System.out.print(Math.min(n - b,c - n));
    }
}
